/**
 *  This file is part of Google App Engine suppport in NetBeans IDE.
 *
 *  Google App Engine suppport in NetBeans IDE is free software: you can
 *  redistribute it and/or modify it under the terms of the GNU General
 *  Public License as published by the Free Software Foundation, either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  Google App Engine suppport in NetBeans IDE is distributed in the hope
 *  that it will be useful, but WITHOUT ANY WARRANTY; without even the
 *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Google App Engine suppport in NetBeans IDE.
 *  If not, see <http://www.gnu.org/licenses/>.
 */
package org.netbeans.modules.j2ee.appengine;

import java.io.File;
import java.io.InputStream;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import javax.enterprise.deploy.model.DeployableObject;
import javax.enterprise.deploy.shared.DConfigBeanVersionType;
import javax.enterprise.deploy.shared.ModuleType;
import javax.enterprise.deploy.spi.DeploymentConfiguration;
import javax.enterprise.deploy.spi.DeploymentManager;
import javax.enterprise.deploy.spi.Target;
import javax.enterprise.deploy.spi.TargetModuleID;
import javax.enterprise.deploy.spi.exceptions.DConfigBeanVersionUnsupportedException;
import javax.enterprise.deploy.spi.exceptions.InvalidModuleException;
import javax.enterprise.deploy.spi.exceptions.TargetException;
import javax.enterprise.deploy.spi.status.ProgressObject;
import org.netbeans.api.project.Project;
import org.netbeans.modules.j2ee.appengine.ide.AppEngineDeployer;
import org.netbeans.modules.j2ee.appengine.ide.AppEngineJ2eePlatformImpl;
import org.netbeans.modules.j2ee.appengine.ide.AppEngineLogger;
import org.netbeans.modules.j2ee.appengine.ide.AppEngineServerMode;
import org.netbeans.modules.j2ee.appengine.ide.AppEngineStartServer;
import org.netbeans.modules.j2ee.appengine.util.AppEnginePluginProperties;
import org.netbeans.modules.j2ee.appengine.util.AppEnginePluginUtils;
import org.netbeans.modules.j2ee.deployment.plugins.api.InstanceProperties;
import org.openide.util.Exceptions;

/**
 * @author Michal Mocnak
 */
public class AppEngineDeploymentManager implements DeploymentManager {

    private final String uri;
    private final AppEngineTarget target;
    private final AppEngineLogger logger;
    private AppEngineModule module;
    private ProgressObject progress;
    private AppEnginePluginProperties properties;
    private AppEngineJ2eePlatformImpl platform;
    private Process process;
    private ExecutorService executor;
    private Project selected;

    public AppEngineDeploymentManager(String uri) {
        this.uri = uri;
        this.properties = new AppEnginePluginProperties(this);
        this.target = new AppEngineTarget(getProperties().getInstanceProperties().getProperty(InstanceProperties.DISPLAY_NAME_ATTR));
        this.logger = AppEngineLogger.getInstance(getUri());
    }

    public String getUri() {
        return uri;
    }

    public AppEngineModule getModule() {
        if (null == module) {
            module = new AppEngineModule(getTarget(),
                    getProperties().getInstanceProperties().getProperty(AppEnginePluginProperties.PROPERTY_HOST),
                    Integer.valueOf(getProperties().getInstanceProperties().getProperty(InstanceProperties.HTTP_PORT_NUMBER)));
        }

        return module;
    }

    public ProgressObject getProgress() {
        if (null == progress) {
            progress = new AppEngineProgressObject(getModule(), false);
        }

        return progress;
    }

    public AppEngineTarget getTarget() {
        return target;
    }

    public AppEnginePluginProperties getProperties() {
        return properties;
    }

    public AppEngineJ2eePlatformImpl getPlatform() {
        if (null == platform) {
            platform = new AppEngineJ2eePlatformImpl(this);
        }

        return platform;
    }

    public Project getSelected() {
        return selected;
    }

    public void setSelected(Project selected) {
        this.selected = selected;
    }

    public Process getProcess() {
        return process;
    }

    public void setProcess(Process process) {
        this.process = process;
    }

    public ExecutorService getExecutor() {
        return executor;
    }

    public void setExecutor(ExecutorService executor) {
        this.executor = executor;
    }

    public Target[] getTargets() throws IllegalStateException {
        return new Target[]{target};
    }

    public TargetModuleID[] getRunningModules(ModuleType arg0, Target[] arg1) throws TargetException, IllegalStateException {
        return new TargetModuleID[]{getModule()};
    }

    public TargetModuleID[] getNonRunningModules(ModuleType arg0, Target[] arg1) throws TargetException, IllegalStateException {
        return new TargetModuleID[]{getModule()};
    }

    public TargetModuleID[] getAvailableModules(ModuleType arg0, Target[] arg1) throws TargetException, IllegalStateException {
        return new TargetModuleID[]{getModule()};
    }

    public DeploymentConfiguration createConfiguration(DeployableObject arg0) throws InvalidModuleException {
        return null;
    }

    public ProgressObject distribute(Target[] target, File file, File plan) throws IllegalStateException {
        // Wait to Google App Engine will be initialized
        while (!logger.contains("The server is running") && !logger.contains("Address already in use")) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            }
        }

        // Get start server object
        AppEngineStartServer start = AppEngineStartServer.getInstance(this);

        // Get progress object
        ProgressObject p = start.getCurrentProgressObject();

        // If the deployer wasn't invoked return
        if (!(p instanceof AppEngineDeployer)) {
            return p;
        }

        // Get checksums
        String checksum = AppEnginePluginUtils.getMD5Checksum(file);
        String checksumToCompare = ((AppEngineDeployer) p).getWarChecksum();

        // If the same as deployed project return
        if (null != checksum && null != checksumToCompare && checksum.equals(checksumToCompare)
                || !start.getMode().equals(AppEngineServerMode.NORMAL)) {
            return p;
        }

        // If not stop server
        if (start.isRunning()) {
            start.stopDeploymentManager();
        }

        // Redeploy in normal mode
        return start.startDeploymentManager();
    }

    public ProgressObject distribute(Target[] arg0, InputStream arg1, InputStream arg2) throws IllegalStateException {
        return getProgress();
    }

    public ProgressObject distribute(Target[] arg0, ModuleType arg1, InputStream arg2, InputStream arg3) throws IllegalStateException {
        return getProgress();
    }

    public ProgressObject start(TargetModuleID[] arg0) throws IllegalStateException {
        return getProgress();
    }

    public ProgressObject stop(TargetModuleID[] arg0) throws IllegalStateException {
        return getProgress();
    }

    public ProgressObject undeploy(TargetModuleID[] arg0) throws IllegalStateException {
        return getProgress();
    }

    public boolean isRedeploySupported() {
        return false;
    }

    public ProgressObject redeploy(TargetModuleID[] arg0, File arg1, File arg2) throws UnsupportedOperationException, IllegalStateException {
        return getProgress();
    }

    public ProgressObject redeploy(TargetModuleID[] arg0, InputStream arg1, InputStream arg2) throws UnsupportedOperationException, IllegalStateException {
        return getProgress();
    }

    public void release() {
    }

    public Locale getDefaultLocale() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Locale getCurrentLocale() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void setLocale(Locale arg0) throws UnsupportedOperationException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Locale[] getSupportedLocales() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isLocaleSupported(Locale arg0) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public DConfigBeanVersionType getDConfigBeanVersion() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isDConfigBeanVersionSupported(DConfigBeanVersionType arg0) {
        return false;
    }

    public void setDConfigBeanVersion(DConfigBeanVersionType arg0) throws DConfigBeanVersionUnsupportedException {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
